
package com.pug.security.jwt;

import com.pug.config.PugRedisCacheTemplate;
import com.pug.pojo.LoginUser;
import com.pug.pojo.SysLoginUser;
import com.pug.service.jwt.IJwtBlackService;
import com.pug.service.jwt.JwtTokenUtils;
import com.pug.service.user.ILoginUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * token过滤器 验证token有效性
 *
 * @author ruoyi
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {


    @Autowired
    @Qualifier("jwtBlackStringService")
    private IJwtBlackService jwtBlackService;
    @Autowired
    private ILoginUserService loginUserService;
    @Autowired
    private PugRedisCacheTemplate pugRedisCacheTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        // 1: 判断当前请求头中是否有token
        String token = JwtTokenUtils.getJwtToken(request);
        if (StringUtils.isEmpty(token)) {
            chain.doFilter(request, response);
        }

        // 判断当前token是不是黑名单里
        if (jwtBlackService.isBlackList(token)) {
            throw new RuntimeException("token is expired black list");
        }

        // 2: 校验token 是否过期 isverfiy = false 代表过期
        boolean isverfiy = JwtTokenUtils.isverfiy(token);
        String tokenKey = "sys:token:string:" + token;
        if (!isverfiy) {
            // 3：如果你过期了就从缓存中去获取token  newh.p.s
            token = pugRedisCacheTemplate.getCacheObject(tokenKey);
        }

        // 获取用户信息
        LoginUser loginUser = JwtTokenUtils.getJwtTokenLoginUser(token);
        if (loginUser == null || pugRedisCacheTemplate.getCacheObject(tokenKey) == null) {
            throw new RuntimeException("token is expired login!!!");
        }

        // 这里负责收集用户对应的信息和权限信息，不做校验和认证
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        // 覆盖信息
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        // 上下文信息同步
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        //2.判断是否需要续期 30分钟就续期
        if (pugRedisCacheTemplate.getExpireTime(tokenKey) < 60 * 40) {
            String newToken = JwtTokenUtils.createToken(loginUser);
            pugRedisCacheTemplate.setCacheObject(tokenKey, newToken, JwtTokenUtils.REDIS_TOKEN_EXPIRATION, TimeUnit.MILLISECONDS);
        }

        chain.doFilter(request, response);
    }
}
